﻿using System;
using XNAGameEngine.Input;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using XNAGameEngine;
using XNAGameEngine.GameObject;
using XNAGameEngine.Collision;
using XNAGameEngine.Utility;

namespace XNAGameEngine
{
    public class Warrior : GameObject2D, ICollidable, IInputListener, IMouseEventListener, IComparable<Warrior>
    {
        #region Characters Stats and Info (private fields)
        private string name;                        //A string to represent the characters name
        private int currentlevel;                   //An int to hold the current character level
        private readonly int maxlevel;              //Maximum possible level a character can attain
                //Can only be set in constuctor
        private int maxhp;                          //Max Healh points avalible at current level
        private int currenthp;                      //Current health of the character
        private int attackpower;                    //The max attack power of a character
        private readonly int maxexperiancepoints;   //Max experiance points that a character can attain which
                //Can only be set in constuctor           will award the character's max level
        private int currentexperiancepoints;        //The current number of experiance points a chracter has 
                                                        //obtained
        private BoundingBox _warriorBox;            //The bounding box of the sprite
        private Rectangle _warriorRectangle;        //A rectangle for the sprite
        public bool IsSelected;                     //A bool to determine if this instance is being
                                                        //moved
        public bool IsMoving;                       //A bool to indicate wether a sprite should be animated
        public bool IsAttacking;                    //A bool to indicate wether a sprite is attacking
        public bool IsAIcontrolled;                 //Indicating AI controlled or not
        public bool IsDead;                         //A bool indication wether the chracter has been killed
        public bool IsBeingAttacked;
        public int normalspeed;                    //The characters speed before being changed in the heap
        public int currentspeed;                   //The characters speed after being changed in the heap
        
        private string charclass;                  //A string to hold the characters type
        private string facing;                     //A string to indicate which direction a character is facing


        public int team;
        
        
                                                    //"South", "East", "North" & "West" are the possible values
        private int xcoord;
        private int ycoord;
        private int map_y;
        private int map_x;

        public skill[] skills;

        private int pose;


        private int str;
        private int dex;
        private int fort;
        private int intel;
        private int will;

        private int currstr;
        private int currdex;
        private int currfort;
        private int currintel;
        private int currwill;

        private Point frameSize;                    //Holds the frame size of the animations
        private Point currentFrame;                 //Holds the current frame the animation is on
        private Point sheetSize;                    //Holds the size of the sprite sheet
        private int timeSinceLastFrame;             //timer for animation
        private int millisecondsPerFrame;           //timer for animation
        private int AttackingTime;                  //timer for animation
        private int AttackingSecondsPerFrame;       //timer for animation

        Texture2D attacked_x;
        int flashx;
        #endregion

        #region Public Properties
        //Name Property
        public string Name                      
        { get { return this.name; } 
            set { this.name = value; } }

        //Current level Property
        public int CurrentLevel                 
        { get { return this.currentlevel; } 
            set { this.currentlevel = value; } }

        //Max Level Getter
        public int MaxLevel                     
        { get { return this.maxlevel; } }

        //Max HP Property
        public int MaxHP                        
        { get { return this.maxhp; }
            set { this.maxhp = value; } }

        //Current HP Property
        public int CurrentHP                    
        { get { return this.currenthp; } 
            set { this.currenthp = value; } }

        //Attack Power Property
        public int AttackPower                  
        { get { return this.attackpower; }
            set { this.attackpower = value; } }

        //Max XP Getter
        public int MaxXP                        
        { get { return this.maxexperiancepoints; } }

        //Current XP Property
        public int CurrentXP                    
        {get { return this.currentexperiancepoints; }
            set { this.currentexperiancepoints = value; } }

        //Character Class Property
        public string CharClass
        { get { return this.charclass; } set { this.charclass = value; } }

        //Post Property
        public int Pose
        { get { return this.pose; } set { this.pose = value; } }

        //Facing Property
        public string Facing
        { get { return this.facing; } set { this.facing = value; } }

        public int Xcoord
        { get { return this.xcoord; } set { this.xcoord = value; } }

        public int Ycoord
        { get { return this.ycoord; } set { this.ycoord = value; } }

        public int Map_y
        { get { return this.map_y; } set { this.map_y = value; } }

        public int Map_x
        { get { return this.map_x; } set { this.map_x = value; } }

        public int Str
        { get { return this.str; } set { this.str = value; } }

        public int Fort
        { get { return this.fort; } set { this.fort = value; } }

        public int Dex
        { get { return this.dex; } set { this.dex = value; } }

        public int Intel
        { get { return this.intel; } set { this.intel = value; } }

        public int Will
        { get { return this.will; } set { this.will = value; } }

        public int CurrStr
        { get { return this.currstr; } set { this.currstr = value; } }

        public int CurrFort
        { get { return this.currfort; } set { this.currfort = value; } }

        public int CurrDex
        { get { return this.currdex; } set { this.currdex = value; } }

        public int CurrIntel
        { get { return this.currintel; } set { this.currintel = value; } }

        public int CurrWill
        { get { return this.currwill; } set { this.currwill = value; } }
        
        #endregion

        #region Constructor
        public Warrior(int warriorID)           //Warrior Constructor
            : base(warriorID)
        {
            this.maxlevel = 10;                 //set the maximum level
            this.maxexperiancepoints = 100;     //set the max exp points
            this.IsSelected = false;            //set IsSelected field   
            this.IsMoving = false;              //set the IsMoving field
            this.IsAttacking = false;           //set IsAttacking
            this.IsDead = false;                //set IsDead
            SetCharacterStats();                //Set the rest of the stats randomly
            Initialize();       
        }
        #endregion

        #region Initialize Method
        public override void Initialize()
        {
            this.name = "";                    //set init name
            this.currentlevel = 1;             //set init level
            this.normalspeed = 0;              //set init normal speed
            this.currentspeed = 0;             //set init current speed
            this.charclass = "";               //set init character class
            this.facing = "South";             //set the facing 
            this.pose = 0;                     //set the pose

            skills = new skill[2];

            //Set the sprite sheet up for animations
            this.frameSize = new Point(32, 48); 
            this.currentFrame = new Point(0, 0);
            this.sheetSize = new Point(4, 5);
            //Set up timing for animations
            this.timeSinceLastFrame = 0;
            this.millisecondsPerFrame = 250;
            this.AttackingTime = 0;
            AttackingSecondsPerFrame = 2100;

            this.IsBeingAttacked = false;
            this.flashx = 0;

            _texture = GameEngine.GameContent.Load<Texture2D>("Content\\Sprites\\Renee4x5");

            attacked_x = GameEngine.GameContent.Load<Texture2D>("Content\\Textures\\attacked_x");

            _warriorRectangle = new Rectangle((int)_position.X, (int)_position.Y,32,48);
                                                //Set a rectangle for the warrior,
                                                    //this sprite is 32x64 origin upper left (0,0)

            _warriorBox = new BoundingBox(new Vector3(0f, 0f, 0f), new Vector3(32f, 48f, 1f));
                                                //Set the bounding box for the warrior

            GameEngine.GetService<IManagerInput>().ToggleInputListening(true, this);
                                                //Object will accept keyboard input
            GameEngine.GetService<IManagerMouseEvents>().ToggleMouseEventListener(true, this);
                                                //Object will accept mouse input

            base.Initialize();
        }
        #endregion

        #region Update
        public override void Update(GameTime gameTime)
        {
            if (IsMoving)
            {
                timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
                if (timeSinceLastFrame > millisecondsPerFrame)
                {
                    timeSinceLastFrame -= millisecondsPerFrame;

                    ++currentFrame.X;
                    if (currentFrame.X >= 4)
                        currentFrame.X = 0;
                }
            }
            if (IsAttacking)
            {
                timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
                if (timeSinceLastFrame > millisecondsPerFrame)
                {
                    timeSinceLastFrame -= millisecondsPerFrame;

                    ++currentFrame.X;
                    if (currentFrame.X >= 4)
                        currentFrame.X = 0;
                }

                AttackingTime += gameTime.ElapsedGameTime.Milliseconds;
                if (AttackingTime > AttackingSecondsPerFrame)
                {
                    AttackingTime -= AttackingSecondsPerFrame;
                    IsAttacking = false;
                }
            }
            if (IsBeingAttacked)
            {
                timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
                if (timeSinceLastFrame > millisecondsPerFrame)
                {
                    timeSinceLastFrame -= millisecondsPerFrame;

                    if (flashx == 0)
                        flashx = 1;
                    else if (flashx == 1)
                        flashx = 0;
                }

                AttackingTime += gameTime.ElapsedGameTime.Milliseconds;
                if (AttackingTime > AttackingSecondsPerFrame)
                {
                    AttackingTime -= AttackingSecondsPerFrame;
                    IsBeingAttacked = false;
                }
            }

            base.Update(gameTime);
        }
        #endregion

        #region Draw
        public override void Draw(GameTime gameTime)
        {
            #region Moving Animation
            if (IsMoving)
            {
                if (facing == "West" || facing == "South")
                    currentFrame.Y = 0;
                else if
                    (facing == "North" || facing == "East")
                    currentFrame.Y = 1;

                if (facing == "West" || facing == "North")
                {
                    GameEngine.SpriteBatch.Draw(
                            _texture,
                            new Rectangle((int)_position.X, (int)_position.Y,
                                32, 48),
                            new Rectangle(currentFrame.X * frameSize.X,
                                currentFrame.Y * frameSize.Y,
                                frameSize.X, frameSize.Y),
                            Color.White, 0, Vector2.Zero, SpriteEffects.None, 0);
                }
                else
                {
                    GameEngine.SpriteBatch.Draw(
                            _texture,
                            new Rectangle((int)_position.X, (int)_position.Y,
                                32, 48),
                            new Rectangle(currentFrame.X * frameSize.X,
                                currentFrame.Y * frameSize.Y,
                                frameSize.X, frameSize.Y),
                            Color.White, 0, Vector2.Zero, SpriteEffects.FlipHorizontally, 0);
                }

            }
            #endregion

            #region Attacking Animation
            else if (IsAttacking)
            {
                if (facing == "West" || facing == "South")
                    currentFrame.Y = 2;
                else if
                    (facing == "North" || facing == "East")
                    currentFrame.Y = 3;

                if (facing == "West" || facing == "North")
                {
                    GameEngine.SpriteBatch.Draw(
                            _texture,
                            new Rectangle((int)_position.X, (int)_position.Y,
                                32, 48),
                            new Rectangle(currentFrame.X * frameSize.X,
                                currentFrame.Y * frameSize.Y,
                                frameSize.X, frameSize.Y),
                            Color.White, 0, Vector2.Zero, SpriteEffects.None, 0);
                }
                else
                {
                    GameEngine.SpriteBatch.Draw(
                            _texture,
                            new Rectangle((int)_position.X, (int)_position.Y,
                                32, 48),
                            new Rectangle(currentFrame.X * frameSize.X,
                                currentFrame.Y * frameSize.Y,
                                frameSize.X, frameSize.Y),
                            Color.White, 0, Vector2.Zero, SpriteEffects.FlipHorizontally, 0);
                }
            }
            #endregion

            #region Dead Animation
            else if (IsDead)
            {
                if (facing == "West")
                {
                    GameEngine.SpriteBatch.Draw(
                            _texture,
                            new Rectangle((int)_position.X, (int)_position.Y,
                                32, 48),
                            new Rectangle(1 * frameSize.X,
                                4 * frameSize.Y,
                                frameSize.X, frameSize.Y),
                            Color.White, 0, Vector2.Zero, SpriteEffects.None, 0);
                }
                else if (facing == "North")
                {
                    GameEngine.SpriteBatch.Draw(
                            _texture,
                            new Rectangle((int)_position.X, (int)_position.Y,
                                32, 48),
                            new Rectangle(3 * frameSize.X,
                                4 * frameSize.Y,
                                frameSize.X, frameSize.Y),
                            Color.White, 0, Vector2.Zero, SpriteEffects.None, 0);
                }
                else if (facing == "South")
                {
                    GameEngine.SpriteBatch.Draw(
                            _texture,
                            new Rectangle((int)_position.X, (int)_position.Y,
                                32, 48),
                            new Rectangle(1 * frameSize.X,
                                4 * frameSize.Y,
                                frameSize.X, frameSize.Y),
                            Color.White, 0, Vector2.Zero, SpriteEffects.FlipHorizontally, 0);
                }
                else if (facing == "East")
                {
                    GameEngine.SpriteBatch.Draw(
                            _texture,
                            new Rectangle((int)_position.X, (int)_position.Y,
                                32, 48),
                            new Rectangle(3 * frameSize.X,
                                4 * frameSize.Y,
                                frameSize.X, frameSize.Y),
                            Color.White, 0, Vector2.Zero, SpriteEffects.FlipHorizontally, 0);
                }

            }
            #endregion

            #region Standing Still Animation
            else
            {
                if (IsBeingAttacked)
                {
                    if (flashx == 1)
                    {
                        GameEngine.SpriteBatch.Draw(
                            attacked_x,
                            new Rectangle((int)_position.X, (int)_position.Y,
                                        32, 48),
                            Color.White);
                    }
                }

                if (facing == "South")
                {
                    GameEngine.SpriteBatch.Draw(
                    _texture,
                    new Rectangle((int)_position.X, (int)_position.Y,
                                    32, 48),
                    new Rectangle(32, 0, 32, 48),
                    Color.White, 0, Vector2.Zero, SpriteEffects.FlipHorizontally, 0);
                }
                if (facing == "West")
                {
                    GameEngine.SpriteBatch.Draw(
                    _texture,
                    new Rectangle((int)_position.X, (int)_position.Y,
                                    32, 48),
                    new Rectangle(32, 0, 32, 48),
                    Color.White, 0, Vector2.Zero, SpriteEffects.None, 0);
                }
                if (facing == "North")
                {
                    GameEngine.SpriteBatch.Draw(
                    _texture,
                    new Rectangle((int)_position.X, (int)_position.Y,
                                    32, 48),
                    new Rectangle(32, 48, 32, 48),
                    Color.White, 0, Vector2.Zero, SpriteEffects.None, 0);
                }
                if (facing == "East")
                {
                    GameEngine.SpriteBatch.Draw(
                    _texture,
                    new Rectangle((int)_position.X, (int)_position.Y,
                                    32, 48),
                    new Rectangle(32, 48, 32, 48),
                    Color.White, 0, Vector2.Zero, SpriteEffects.FlipHorizontally, 0);
                }
            }   
            #endregion
        }
        #endregion 

        #region Move X and Y Position
        public void MovePosition(int x, int y)
        {
            _position.X = x + 16;
            _position.Y = y - 30;
        }
        #endregion

        #region Randomly Set Character Stats
        public void SetCharacterStats()
        {
            if (this.IsAIcontrolled == false)
            {
                this.normalspeed = MathToolbox.GetRandom.Next(2, 5);
                this.currentspeed = this.normalspeed;
                //Console.WriteLine("CurrentSpeed = " + currentspeed);
                this.maxhp = 100;
                this.currenthp = maxhp;
                this.attackpower = MathToolbox .GetRandom.Next(25, 40);
            }
            else
            {
                this.normalspeed = MathToolbox.GetRandom.Next(2, 5);
                this.currentspeed = this.normalspeed;
                //Console.WriteLine("CurrentSpeed = " + currentspeed);
                this.maxhp = 50;
                this.currenthp = maxhp;
                this.attackpower = MathToolbox.GetRandom.Next(10, 20);
            }
        }
        #endregion

        #region Kill Character
        public void KillCharacter()
        {
            this.IsMoving = false;
            this.IsAttacking = false;
            this.IsDead = true;
            this.IsBeingAttacked = false;
        }
        #endregion

        #region Set Sprite Texture
        public void SetTexture(int i)
        {
            switch (i)
            {
                case 1: _texture = GameEngine.GameContent.Load<Texture2D>("Content\\Sprites\\Renee4x5");
                    break;
                case 2: _texture = GameEngine.GameContent.Load<Texture2D>("Content\\Sprites\\Kent4x5");
                    break;
                case 3: _texture = GameEngine.GameContent.Load<Texture2D>("Content\\Sprites\\Wolf4x5");
                    break;
                case 4: _texture = GameEngine.GameContent.Load<Texture2D>("Content\\Sprites\\Dante4x5");
                    break;
                case 5: _texture = GameEngine.GameContent.Load<Texture2D>("Content\\Sprites\\BadGuy4x5");
                    break;
            }
        }
        #endregion

        #region Clean Up
        public void Cleanup()
        {                                              
            GameEngine.GetService<IManagerMouseEvents>().ToggleMouseEventListener(false, this);
            GameEngine.GetService<IManagerInput>().ToggleInputListening(false, this);
        }
        #endregion

        #region Destroy
        public override void Destroy()
        {
            base.Destroy();
        }
        #endregion

        #region ICollidable Members

        public BoundingBox BoundingBox
        {
            get
            {
                return _warriorBox;
            }
            set
            {}
        }

        public void Collided(CollisionMessage intCollidedWith)
        {
            Console.WriteLine("This Warrior " + this._objectId + " has been hit by an object with object ID " + intCollidedWith._objectId);
        }

        #endregion

        #region IInputListener Members

        public void InputPressed(InputMessage input)
        {
            
        }

        public void InputReleased(InputMessage input)
        {
            
        }

        public void InputHeld(InputMessage input)
        {
            if (this.IsSelected == true)
            {
                switch (input._key)
                {
                    case Keys.Left:
                        if (_position.X <= 0)
                        {
                            _position.X = 0;
                        }
                        else
                        {
                            _position.X--;
                            _warriorRectangle.X--;
                        }
                        break;
                    case Keys.Right:
                        if (_position.X >= (800 - _texture.Width))
                        {
                            _position.X = (800 - _texture.Width);
                        }
                        else
                        {
                            _position.X++;
                            _warriorRectangle.X++;
                        }
                        break;
                    case Keys.Up:
                        if (_position.Y <= 0)
                        {
                            _position.Y = 0;
                        }
                        else
                        {
                            _position.Y--;
                            _warriorRectangle.Y--;
                        }
                        break;
                    case Keys.Down:
                        if (_position.Y >= (600 - _texture.Height))
                        {
                            _position.Y = (600 - _texture.Height);
                        }
                        else
                        {
                            _position.Y++;
                            _warriorRectangle.Y++;
                        }
                        break;
                }
            }
        }

        public event ManagerInput.InputRegisterListenerEventHandler ThrowUnregisterListenerEvent;

        #endregion

        #region IMouseEventListener Members

        Rectangle IMouseEventListener.BoundingBox
        {
            get { return _warriorRectangle; }
        }

        public void OnMouseEnter()
        {
            _textureTint = Color.Red;
        }

        public void OnMouseExit()
        {
            _textureTint = Color.Yellow;
        }

        public void OnMouseClick(MouseClick input)
        {
            if (input == MouseClick.LEFT)
            {
                IsSelected = true;
            }
            if (input == MouseClick.RIGHT)
            {
                IsSelected = false;
            }
        }

        #endregion

        #region IComparable<Warrior> Members

        public int CompareTo(Warrior other)
        {
            if (currentspeed < other.currentspeed)
                return 1;

            if (currentspeed >= other.currentspeed)
                return 0;

            return -1;
        }

        #endregion
    }


}
